home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / bin / apport-collect < prev    next >
Encoding:
Text File  |  2009-09-25  |  5.5 KB  |  177 lines

  1. #!/usr/bin/python
  2.  
  3. # Download a Launchpad bug report, get its source package, check if it has
  4. # apport hooks, and if so, run and upload them.
  5. #
  6. # Copyright (c) 2009 Canonical Ltd.
  7. # Author: Martin Pitt <martin.pitt@ubuntu.com>
  8. #
  9. # This program is free software; you can redistribute it and/or modify it
  10. # under the terms of the GNU General Public License as published by the
  11. # Free Software Foundation; either version 2 of the License, or (at your
  12. # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
  13. # the full text of the license.
  14.  
  15. import sys, os.path, optparse, tempfile, atexit, shutil, re, email
  16. from glob import glob
  17.  
  18. import apport
  19.  
  20. bug_target_re = re.compile(
  21.     r'/ubuntu/(?:(?P<suite>[^/]+)/)?\+source/(?P<source>[^/]+)$')
  22.  
  23. try:
  24.     import launchpadlib.errors
  25.     from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT, EDGE_SERVICE_ROOT
  26.     from launchpadlib.credentials import Credentials
  27. except ImportError:
  28.     print >> sys.stderr, 'Please install the package "python-launchpadlib".'
  29.     sys.exit(1)
  30.  
  31. def login(launchpad_instance=EDGE_SERVICE_ROOT):
  32.     '''Log into Launchpad.
  33.     
  34.     This reads/saves credentials, and returns a Launchpad instance.
  35.     '''
  36.     cache_dir = tempfile.mkdtemp()
  37.     atexit.register(shutil.rmtree, cache_dir)
  38.  
  39.     cred_dir = os.path.expanduser('~/.cache/apport')
  40.     if not os.path.isdir(cred_dir):
  41.         os.makedirs(cred_dir)
  42.     cred = os.path.join(cred_dir, 'launchpad.credentials')
  43.  
  44.     if os.path.exists(cred):
  45.         # use existing credentials
  46.         credentials = Credentials()
  47.         credentials.load(open(cred))
  48.         launchpad = Launchpad(credentials, launchpad_instance, cache_dir)
  49.     else:
  50.         # get credentials and save them
  51.         try:
  52.             launchpad = Launchpad.get_token_and_login('apport-collect',
  53.                     launchpad_instance, cache_dir)
  54.         except launchpadlib.errors.HTTPError, e:
  55.             print >> sys.stderr, 'Error connecting to Launchpad: %s\nYou have to allow "Change anything" privileges.' % str(e)
  56.             sys.exit(1)
  57.         f = open(cred, 'w')
  58.         os.chmod(cred, 0600)
  59.         launchpad.credentials.save(f)
  60.         f.close()
  61.  
  62.     return launchpad
  63.  
  64. def upload(report, bug):
  65.     '''Upload collected information to Launchpad bug.'''
  66.  
  67.     print 'Uploading additional information to Launchpad bug...'
  68.  
  69.     # we want to reuse the knowledge of write_mime() with all its different input
  70.     # types and output formatting; however, we have to dissect the mime ourselves,
  71.     # since we can't just upload it as a blob
  72.     mime = tempfile.TemporaryFile()
  73.     report.write_mime(mime)
  74.     mime.flush()
  75.     mime.seek(0)
  76.     msg = email.message_from_file(mime)
  77.     msg_iter = msg.walk()
  78.  
  79.     # first part is the multipart container
  80.     part = msg_iter.next()
  81.     assert part.is_multipart()
  82.  
  83.     # second part should be an inline text/plain attachments with all short
  84.     # fields
  85.     part = msg_iter.next()
  86.     assert not part.is_multipart()
  87.     assert part.get_content_type() == 'text/plain'
  88.     
  89.     print'   short text data...'
  90.     bug.newMessage(content=part.get_payload(decode=True), 
  91.         subject='apport-collect data')
  92.  
  93.     # other parts are the attachments:
  94.     for part in msg_iter:
  95.         print '   attachment: %s...' % part.get_filename()
  96.         bug.addAttachment(comment='', data=part.get_payload(decode=True),
  97.             filename=part.get_filename(), is_patch=False)
  98.  
  99. def collect(report, package):
  100.     '''Collect information for given package.'''
  101.  
  102.     print 'Collecting apport information for source package %s...' % package
  103.     try:
  104.         report.add_package_info(package)
  105.     except ValueError:
  106.         # this happens for source package tasks which do not have an identical
  107.         # binary package name
  108.         pass
  109.     report.add_hooks_info()
  110.  
  111. #
  112. # main
  113. #
  114.  
  115. optparser = optparse.OptionParser('%prog [options] <Launchpad bug number>')
  116. optparser.add_option('-p', '--package', 
  117.     help="Collect information for this package. If not given, it will be inferred from the bug report's source package tasks.",
  118.     type='string', dest='package')
  119. (opts, args) = optparser.parse_args()
  120.  
  121. if len(args) != 1:
  122.     optparser.error('incorrect number of arguments; use --help for a short online help')
  123.     sys.exit(1)
  124.  
  125. (bug_number,) = args
  126.  
  127. print 'Logging into Launchpad...'
  128. if os.getenv('APPORT_STAGING'):
  129.     lp = login(STAGING_SERVICE_ROOT)
  130. else:
  131.     lp = login()
  132.  
  133. print 'Downloading bug...'
  134. bug =  lp.bugs[int(bug_number)]
  135.  
  136. report = apport.Report('Bug')
  137.  
  138. print 'Bug title:', bug.title
  139. if opts.package:
  140.     collect(report, opts.package)
  141. else:
  142.     # determine bug tasks and collect for those
  143.     for task in bug.bug_tasks:
  144.         match = bug_target_re.search(task.target.self_link)
  145.         if not match:
  146.             print 'Ignoring task', task.target
  147.             continue
  148.         if task.status in ('Invalid', "Won't Fix", 'Fix Released'):
  149.             print 'Ignoring task %s because it is closed' % task.target
  150.             continue
  151.         src = match.group('source')
  152.         report['SourcePackage'] = src
  153.         report['Package'] = src # no way to find this out
  154.         collect(report, src)
  155.  
  156. report.add_os_info()
  157. report.add_user_info()
  158. report.add_proc_environ()
  159.  
  160. # delete the uninteresting keys
  161. del report['ProblemType']
  162. del report['Date']
  163. try:
  164.     del report['SourcePackage']
  165. except KeyError:
  166.     pass
  167.  
  168. if len(report.keys()) == 0:
  169.     print 'No additional information collected.'
  170.     sys.exit(0)
  171.  
  172. try:
  173.     upload(report, bug)
  174. except launchpadlib.errors.HTTPError, e:
  175.     print >> sys.stderr, 'Error connecting to Launchpad: %s\nYou have to allow "Change anything" privileges.' % str(e)
  176.     sys.exit(1)
  177.